<?php
namespace app\common\model\system;

use app\command\HistoryTrade;
use app\command\HttpServer;
use app\common\model\base\A3Mall;
use think\facade\Cache;

class SqlToRedis extends A3Mall
{
    protected $name = "coin_rule";

    // 设置 store 中的redis 类型
    private $storeRedis = 'file';


    // 缓存保存的key
    private $hashKey = 'sqll_to_redis_cache';

    /**
     * 类型对应的键
     * @var string[]
     */
    private $valueCacheKeyList = [
        'userRule'  => 'user_rule',
        'tradeMonitor'   => 'trade_monitor',

        'ruleCalculationConfig'   => 'rule_calculation_config',  //保存规则信息缓存
    ];

    private $autoRefreshTime_thade = 4; //自动刷新订单状态时间，单位秒；0表示不自动刷新


    private $autoRefreshTime = 10;  //redis缓存自动刷新时间，单位秒；0表示不自动刷新


    /*
     * 规则配置过期时间 ，单位 s
     */
    private $ruleConfigExpire = 180;    // 配置有效时间 3 分钟


    /**
     * @param int $expire 期限
     */
    public function getRuleConfig($expire = -1) {
        return $this->redisGet($this->valueCacheKeyList['ruleCalculationConfig'],$expire < 0?$this->ruleConfigExpire:$expire);
    }

    /**
     * 设置规则配置缓存
     * @param array $config 配置信息
     * @return bool
     */
    public function saveRuleConfig(array $config) {
        return $this->redisSet($this->valueCacheKeyList['ruleCalculationConfig'],$config);
    }


    /**
     * 获取用户规则记录信息
     * @param int $platform 平台
     * @param bool $refresh 是否刷新
     * @return array
     */
    public function getUserRule($platform = null,$refresh = false,$noRedis = false) {
        if($refresh && !$noRedis) {
            // 主进程刷新属性用户规则
            HttpServer::request(HttpServer::CMD_LIST['REFRESH'],['type'=>'userRule']);
           /* for($i=0;$i<3;++$i) {
                try {
                    HistoryTrade::tcpTableQuery('userRuleRefresh',$i);  //除不使用redis之外，其他直接返回操作结果
                }catch (\Exception $e) {
                }
            }*/
            return true;
        }
        $platform = is_null($platform)?1:$platform;
        $redisKey = $this->valueCacheKeyList['userRule'] . '_' . $platform;
        if($noRedis || $refresh || !($result = $this->redisGet($redisKey,$this->autoRefreshTime))) {
            $result = [];
            if($list = $this::name('coin_rule')->alias('rule')
                ->join('users user','user.id=rule.user_id AND user.status=0','INNER')
                ->join('coin coin','coin.id=rule.coin_id AND coin.platform=' . $platform . ' AND coin.status=1','INNER')
                ->join('users_key key','key.id=rule.user_id','INNER')
                ->join('coin_rule_cover cover','cover.coin_rule_id=rule.id','INNER')
                ->join('coin_rule_run run_details','run_details.id=rule.coin_rule_run_id','LEFT')
                ->field([
                    'rule.*',
                    'code',
                    'key.account_id','key.access_key','key.secret_key',
                    'cover.frequency','cover.overlap','cover.callback',
                    'run_details.unique_id','run_details.cover_times','run_details.cover_times_auto','run_details.cover_times_manual','run_details.amount','run_details.quantity','run_details.unit_price','run_details.cover_unit_price','run_details.stop_unit_price','run_details.version',
                    'run_details.last_buy_err_time','run_details.last_sell_err_time',

                    'user.vip','user.vip_expire','user.local_balance','user.has_service_charge'
                ])
                ->order([
                    'cover.coin_rule_id' => 'ASC',
                    'cover.frequency' => 'ASC'
                ])
                ->where([
                    'is_open'   => 1,
                ])/*->fetchSql()*/->select()) {
                $tmpList = [];  //临时列表
                foreach($list as $value) {
                    $value = $value->getData();
                    $ruleId = $value['id'];
                    if(!array_key_exists($ruleId,$tmpList)) {
                        $tmpList[$ruleId] = array_merge($value,[
                            'coverList' => [],
                        ]);
                    }
                    // 获取补仓规则
                    $tmpList[$ruleId]['coverList'][] = [
                        'frequency' => $value['frequency'],
                        'overlap' => $value['overlap'],
                        'callback' => $value['callback'],
                    ];
                }

                // 过滤未完整数据
                foreach($tmpList as $value) {
                    $num = count($value['coverList']);
                    if($value['num'] != $num || $value['num'] != $value['coverList'][$num -1]['frequency']) {
                        continue;
                    }

                    // 判断是否有监控选项
                    if(!\app\common\model\users\Users::isMonitor($value)) {
                        continue;
                    }

                    $result[] = $value;

                }

                if(!$noRedis) { // 判断为不需要缓存处理
                    // 设置redis缓存信息
                    $this->redisSet($redisKey,$result);
                }

            }
        }
        return $result;
    }



    /**
     * 获取实时监控订单状态列表
     * @param bool $refresh 是否刷新
     * @return array
     */
    public function getTradeMonitor($refresh = false) {
        $redisKey = $this->valueCacheKeyList['tradeMonitor'];
        if($refresh || !($result = $this->redisGet($redisKey,$this->autoRefreshTime_thade))) {
            $result = [];
            if($list = $this::name('coin_rule_run_trade')->alias('trade')
                ->join('users_key key','key.id=trade.user_id','INNER')
                ->join('coin coin','coin.id=trade.coin_id','INNER')
                ->field([
                    'trade.*',

                    'key.account_id','key.access_key','key.secret_key',
                    'coin.code',
                ])
                ->order([
                    'trade.id' => 'DESC',
                ])
                ->where([
                    ['trade.status','between',[1,3]],
            //        ['trade.request_status','<>',1],
                ])->select()) {

                $result = [];
                $nowTime = time();
                foreach($list as $value) {
                    $value = $value->getData();
                    if($value['request_status'] == 1 && $nowTime - $value['create_time'] < 60) {
                        continue;
                    }
                    $result[$value['client_order_id']] = $value;
                }
                // 设置redis缓存信息
                $this->redisSet($redisKey,$result);
            }
        }
        return $result;
    }


    /**
     * 返回哈希表中，所有的字段和值
     * @param  string $table 表名
     * @return array   返回键值对数组
     */
    public function hgetall($table)
    {
        return $this->redis()->hgetall($table);
    }

    /**
     * 为哈希表中的字段赋值
     * @param  string  $table  哈希表名
     * @param  string  $column 字段名
     * @param  string|array  $value  字段值
     * @param  int $expire 过期时间, 如果不填则不设置过期时间
     * @return int  如果成功返回 1，否则返回 0.当字段值已存在时覆盖旧值并且返回 0
     */
    public function hset($table, $column, $value, $expire=0)
    {
        return $this->redis()->hset($table, $column, $value, $expire);
    }


    /**
     * 删除哈希表 key 中的一个或多个指定字段，不存在的字段将被忽略
     * @param  string $table  表名
     * @param  string $column 字段名
     * @return int  返回被成功删除字段的数量，不包括被忽略的字段,(删除哈希表用self::del($table))
     */
    public function hdel($table, $columns){
        return $this->redis()->hdel($table,$columns);
    }


    /**
     * 获取 redis 缓存数据
     * @param $key 键
     * @param $autoRefreshTime 自动刷新时间
     * @return |null 返回值
     */
    private function redisGet($key,$autoRefreshTime) {
        $redis = $this->redis();
        if($this->storeRedis == 'redis') {
            $result = $redis->hget($this->hashKey,$key);
        } else {
            $result = $redis->get($this->hashKey . '_' . $key);
        }
        if($result) {
            if(!$result = json_decode($result,true)) {
                return null;
            }
            if(!array_key_exists('time',$result) || !array_key_exists('value',$result) ||
                ($this->autoRefreshTime > 0 && time() - $result['time'] > $autoRefreshTime)   //过期获取为空
            ) {
                $result = null;
            } else {
                $result = $result['value'];
            }
        }
        return $result?$result:null;
    }

    /**
     * 设置redis缓存
     * @param $key key
     * @param $value 值
     * @return bool
     */
    private function redisSet($key,$value)
    {
        $value = [
            'time'  => time(),
            'value' => $value,
        ];
        $redis = $this->redis();
        if($this->storeRedis == 'redis') {
            $result = $redis->hset($this->hashKey,$key,json_encode($value));
        } else {
            $result = $redis->set($this->hashKey . '_' . $key,json_encode($value));
        }
        return $result?true:false;
    }


    /**
     * 获取 redis 类
     * @return \think\cache\Driver
     */
    private function redis() {
        return Cache::store($this->storeRedis);
    }

    /**
     * 重启redis
     */
    public function restart() {
        try{

        }catch (\Exception $e) {
            $this->redis()->restart();
        }
    }


}